<?php


namespace app\api\model;


use app\api\utils\JWT;
use app\lib\exception\BaseException;
use DateInterval;
use DateTime;
use think\Db;
use think\Exception;
use think\Model;
use think\Request;

class InfoModel extends Model
{
    protected $table = 'cash_info';

    public static function getInfos($month)
    {
        $books = Db::query("select * from cash_book where state = 1 and month = ? order by category asc, id asc", [$month]);;

        $objs = [];
        $category_B = [];
        $category_B_titles = [];
        foreach ($books as $book) {
            if ($book['category'] != 'A') {
                if ($book['category'] == 'B') {
                    $objs['B'][] = $book;
                    $category_B[] = $book['id'];
                    $category_B_titles[] = $book['title'];
                } else {
                    $objs[$book['category']][] = $book;
                }
            }
        }

        $infos = Db::query("select cash_info.*, cash_book.title book_name from cash_info left join cash_book on cash_book.id = cash_info.cb_id where cash_info.month = ? order by cash_info.index asc", [$month]);
        $list = [];
        foreach ($infos as $value) {
            $value['expand'] = true;
            if ($value['category'] == 'A' || $value['category'] == 'B') {
                if ($value['category'] == 'B' && $value['cb_id'] != null) {
                    $value['detail_income_' . $value['cb_id']] = $value['detail_income'];
                    $value['detail_outcome_' . $value['cb_id']] = $value['detail_outcome'];
                }
                $list['AB'][] = $value;
            } else {
                $list[$value['category']][] = $value;
            }
        }
        $fields = array_keys(array_values($list)[0][0]);
        $temp = [];
        foreach ($fields as $field) {
            $temp[$field] = null;
            $temp['expand'] = true;
            $temp['pid'] = 0;
            $temp['index'] = null;
        }

        $array = [];
        $values = array_values($list);
        for ($index = 0; $index < count($values); $index++) {
            $value = $values[$index];
            $temp['type'] = $index == 0 ? -1 : 2;
            $temp['category'] = $value[0]['category'];
            if ($temp['category'] == 'A') {
                $temp['category'] = 'B';
            }
            $temp['id'] = $temp['category'] == 'B' ? 'AB' : $temp['category'];
            $temp['is_light'] = InfoModel::where('is_light', 1)->where('month', $month)->where('category', $temp['category'])->count() > 0 ? 1 : null;
            $temp['title'] = $index == 0 ? implode('/', $category_B_titles) : $value[0]['book_name'];
            for ($i = 0; $i < count($value); $i++) {
                if ($value[$i]['record'] != null) {
                    $value[$i]['record'] = json_decode($value[$i]['record'], true);
                }
                $temp['record'] = 1;
                $value[$i]['pid'] = $temp['id'];
                $value[$i]['type'] = 3;
                $value[$i]['delPop'] = false;
            }
            $array[] = array_merge([$temp], $value);
        }

        $balance = null;
        for ($i = 0; $i < count($array[0]); $i++) {
            $balance = bcsub(bcadd(bcadd($balance, $array[0][$i]['money'], 2), $array[0][$i]['detail_income'],2), $array[0][$i]['detail_outcome'], 2);
//            $balance = bcadd(bcadd($array[0][$i]['detail_income'], $array[0][$i]['detail_outcome'],2), $array[0][$i]['money'], 2) + $balance;
            if ($array[0][$i]['money'] == null && $array[0][$i]['detail_income'] == null && $array[0][$i]['detail_outcome'] == null) {
                if($array[0][$i]['category'] == 'A'){
                    $array[0][$i]['balance'] = $balance;
                }else{
                    $array[0][$i]['balance'] = null;
                }
            } else {
                $array[0][$i]['balance'] = $balance;
            }
        }

        $plan = PlanModel::get(['month' => $month]);
        return [
            'max_month' => PlanModel::max('month'),
            'plan' => $plan,
            'categorys' => array_values($objs),
            'data' => $array,
            'total' => self::getTotal($month, $category_B)
        ];
    }

    public static function getTotal($month, $category_B)
    {
//        港币金额
        $detail_money = Db::query("SELECT IFNULL(sum(detail_money), 0) detail_money from cash_info where category = 'C' and month = ?", [$month])[0]['detail_money'];
//        预算汇率
        $budget_rate = Db::query("SELECT rate budget_rate from cash_plan where `month` = ?", [$month])[0]['budget_rate'];
        $data = Db::query("SELECT IFNULL(sum(detail_payment), 0) detail_payment, IFNULL(sum(income), 0) income, IFNULL(sum(outcome), 0) outcome, IFNULL(sum(money), 0) money, IFNULL(sum(detail_income), 0) detail_income, IFNULL(sum(detail_outcome), 0) detail_outcome from cash_info where `month` = ?", [$month])[0];
//        垫付
        $detail_payment = $data['detail_payment'];
//        流水收入
        $income = $data['income'];
//        流水支出
        $outcome = $data['outcome'];
//        实际金额
        $money = $data['money'];
//        余额
        $balance = bcadd(bcsub($data['detail_income'], $data['detail_outcome'], 2), $money, 2);

        $detail_rmb = Db::query("SELECT IFNULL(sum(detail_rmb), 0) detail_rmb from cash_info where month = ? and category in ('B', 'C');", [$month])[0]['detail_rmb'];
//        人民币
        $detail_rmb = bcsub($detail_rmb, $balance, 2);
        $detail_rmb_footer = Db::query("SELECT IFNULL(sum(detail_rmb), 0) detail_rmb from cash_info where month = ? and category in ('E', 'F');", [$month])[0]['detail_rmb'];
        $detail_rmb_footer = bcadd($detail_rmb_footer, $detail_rmb, 2);

        $category_B_data = Db::query("SELECT cb_id, IFNULL(sum(detail_income), 0) detail_income, IFNULL(sum(detail_outcome), 0) detail_outcome from cash_info where month = ? and category = 'B' group by cb_id", [$month]);
        $list = [];
        foreach ($category_B_data as $temp) {
            $list[$temp['cb_id']] = $temp;
        }
        $fields = [];
        $fields_footer = [];
        $light_fields = [
            'balance' => ($balance > 100 || $balance < -100) ? 'is_warning' : '',
            'real_rate' => Db::query("SELECT count(1) count from cash_info where month = ? and category = 'C' and detail_money is not null and real_rate is null;", [$month])[0]['count'] ? 'is_warning' : '',
            'income' => $income != $outcome ? 'is_warning' : '',
            'outcome' => $income != $outcome ? 'is_warning' : '',
        ];
        foreach ($category_B as $category) {
            $fields['detail_income_' . $category] = null;
            $fields['detail_outcome_' . $category] = null;
            $fields_footer['detail_income_' . $category] = null;
            $fields_footer['detail_outcome_' . $category] = null;
            if (isset($list[$category])) {

                $income_cb_id = Db::query("SELECT IFNULL(sum(income), 0) income, IFNULL(sum(outcome), 0) outcome from cash_info where month = ? and cb_id = ?;", [$month, $category])[0];

                $fields['detail_income_' . $category] = bcsub($list[$category]['detail_income'], $income_cb_id['income'], 2);
                $fields['detail_outcome_' . $category] = bcsub($list[$category]['detail_outcome'], $income_cb_id['outcome'], 2);
                $light_fields['detail_income_' . $category] = $list[$category]['detail_income'] != 0 ? 'is_warning' : '';
                $light_fields['detail_outcome_' . $category] = $list[$category]['detail_outcome'] != 0 ? 'is_warning' : '';
            } else {
                $fields['detail_income_' . $category] = '0.00';
                $fields['detail_outcome_' . $category] = '0.00';
            }
        }
        $plan = PlanModel::get(['month' => $month]);
        $warning_fields = [];
        if ($plan['has_change'] == null) {
            foreach ($light_fields as $key => $value) {
                if ($value == 'is_warning') {
                    $warning_fields[] = $key;
                }
            }
        }
        return [
            'warning_fields' => $warning_fields,
            'header' => array_merge($fields, [
                'detail_money' => $detail_money,
                'budget_rate' => $budget_rate,
                'real_rate' => null,
                'detail_rmb' => $detail_rmb ? $detail_rmb * 1 : '0.00',
                'detail_payment' => $detail_payment,
                'income' => $income,
                'outcome' => $outcome,
                'balance' => $balance ? ($balance * 1) : '0.00',
                'money' => $money,
                'id' => null,
                'cb_id' => null,
                'book_name' => null,
                'category' => null,
                'sort_num' => null,
                'title' => null,
                'month' => null,
                'issue' => null,
                'weekday' => null,
                'day' => null,
                'remark' => null,
                'state' => null,
                'type' => 1,
                'expand' => true
            ]),
            'footer' => array_merge($fields_footer, [
                'detail_money' => null,
                'budget_rate' => null,
                'real_rate' => null,
                'detail_rmb' => $detail_rmb_footer,
                'detail_payment' => null,
                'income' => null,
                'outcome' => null,
                'balance' => null,
                'money' => null,
                'id' => null,
                'cb_id' => null,
                'book_name' => null,
                'category' => null,
                'sort_num' => null,
                'title' => '本月实际消费金额：',
                'month' => null,
                'issue' => null,
                'weekday' => null,
                'day' => null,
                'remark' => null,
                'state' => null,
                'type' => 4,
                'expand' => true
            ])
        ];
    }

    public static function getInfoWithBook($month, $cb_id)
    {
        $count = Db::table('cash_info')->where("month = " . $month)->where("cb_id = " . $cb_id)->count();
        if ($count != 0) {
            throw new BaseException([
                'msg' => '不可以关闭：该账本在当前明细表存在记录',
                'code' => 9527,
                'errorCode' => 400
            ]);
        }
    }

    public static function sortList($month, $category)
    {
        return Db::transaction(function () use ($month, $category) {
            if ($category == 'C') {
                $list = Db::query('SELECT * from cash_info where category = "C" and month = ? order by isnull(issue) asc, issue asc, isnull(title) asc;', [$month]);
            } else {
                $list = Db::query('SELECT * from cash_info where (category = "A" or category = "B") and month = ? order by isnull(issue) asc, issue asc, isnull(title) asc;', [$month]);
            }
            $min_index = min(array_column($list, 'index'));
            $infoModel = new InfoModel;
            foreach ($list as $index => $data) {
                $array[] = [
                    'id' => $data['id'],
                    'index' => $min_index + $index
                ];
            }
            $infoModel->saveAll($array);
            $result = [
                'array' => $array,
            ];
            if ($category != 'C') {
                $result['rows'] = self::updateBetchBalance($month);
            }
            return $result;
        });

    }

    public static function updateLight($id)
    {
        $InfoModel = InfoModel::get($id);
        InfoModel::where('id', $id)->update(['is_light' => $InfoModel['is_light'] == 1 ? ['exp', 'null'] : 1]);
        return [
            'single' => $InfoModel['is_light'] == 1 ? null : 1,
            'group' => InfoModel::where('is_light', 1)->where('month', $InfoModel['month'])->where('category', $InfoModel['category'])->count() > 0 ? 1 : null
        ];
    }

    public static function saveInfo($position, $id)
    {
        return Db::transaction(function () use ($position, $id) {
            try {
                $InfoModel = InfoModel::get($id);
                $infos = Db::query("select cash_info.* from cash_info where cash_info.month = ? order by cash_info.index asc", [$InfoModel['month']]);
                $index = $position == 'upRow' ? ($InfoModel['index'] - 1) : $InfoModel['index'];
                $right_part = array_reverse(array_slice($infos, $index));
                $sort = new InfoModel;
                foreach ($right_part as $data) {
                    $array[] = [
                        'id' => $data['id'],
                        'index' => 1 + $data['index']
                    ];
                }
                $sort->saveAll($array);
                $category = $InfoModel['category'] == 'A' ? 'B' : $InfoModel['category'];
                $item = new InfoModel([
                    'category' => $category,
                    'cb_id' => $category == 'C' ? $InfoModel['cb_id'] : null,
                    'source' => 'manually',
                    'month' => $InfoModel['month'],
                    'index' => $right_part[count($right_part) - 1]['index']
                ]);
                $item->save();
                $base_item = InfoModel::get($item['id']);
                $base_item['expand'] = true;
                $base_item['type'] = 3;
                $base_item['delPop'] = false;
                $base_item['title'] = null;
                $base_item['pid'] = ($InfoModel['category'] == 'A' || $InfoModel['category'] == 'B') ? 'AB' : $InfoModel['category'];
                return $base_item;
            } catch (Exception $ex) {
                throw new BaseException([
                    'code' => 9527,
                    'msg' => '数据发生变化',
                    'errorCode' => 400
                ]);
            }
        });
    }

    public static function deleteInfo($id)
    {
        return Db::transaction(function () use ($id) {
            $InfoModel = InfoModel::get($id);
            if (null == $InfoModel) {
                throw new BaseException([
                    'code' => 9527,
                    'msg' => '数据不存在已被删除',
                    'errorCode' => 400
                ]);
            }
            if (!(($InfoModel['category'] == 'B' || $InfoModel['category'] == 'C') && $InfoModel['source'] == 'manually')) {
                throw new BaseException([
                    'code' => 9527,
                    'msg' => '只有 B/C 类账本，记录来源为“手动添加”，才能删除',
                    'errorCode' => 400
                ]);
            }
            $infos = Db::query("select cash_info.* from cash_info where cash_info.month = ? order by cash_info.index asc", [$InfoModel['month']]);
            foreach ($infos as $info) {
                $category = $info['category'] == 'A' ? 'B' : $info['category'];
                $map[$category][] = $info;
            }
            $count = 0;
            if (!empty($map[$InfoModel['category']])) {
                $count = count($map[$InfoModel['category']]);
            }
            if ($count == 1) {
                //如果“账本名称行”仅剩一条记录：删除成功后，自动生成一条空白行
                $InfoModel->record = null;
                $InfoModel->title = null;
                $InfoModel->issue = null;
                $InfoModel->weekday = null;
                $InfoModel->day = null;
                $InfoModel->income = null;
                $InfoModel->outcome = null;
                $InfoModel->money = null;
                $InfoModel->remark = null;
                $InfoModel->detail_money = null;
                $InfoModel->budget_rate = null;
                $InfoModel->real_rate = null;
                $InfoModel->detail_rmb = null;
                $InfoModel->detail_payment = null;
                $InfoModel->detail_income = null;
                $InfoModel->detail_outcome = null;
                $InfoModel->is_light = null;
                if ($InfoModel['category'] != 'C') {
                    $InfoModel->cb_id = null;
                }
                $InfoModel->save();

                $base_item = InfoModel::get($InfoModel['id']);
                $base_item['expand'] = true;
                $base_item['type'] = 3;
                $base_item['delPop'] = false;
                $base_item['title'] = null;
                $base_item['pid'] = ($InfoModel['category'] == 'A' || $InfoModel['category'] == 'B') ? 'AB' : $InfoModel['category'];

                $books = Db::query("select * from cash_book where state = 1 and month = ? and category = 'B' order by category asc, id asc", [$InfoModel['month']]);;
                $category_B = array_column($books, 'id');
                $result = [
                    'total' => self::getTotal($InfoModel['month'], $category_B),
                    'cur_row' => $base_item,
                    'group' => InfoModel::where('is_light', 1)->where('month', $InfoModel['month'])->where('category', $InfoModel['category'])->count() > 0 ? 1 : null
                ];
            } else {
                $right_part = array_reverse(array_slice($infos, $InfoModel['index']));
                $sort = new InfoModel;
                foreach ($right_part as $data) {
                    $array[] = [
                        'id' => $data['id'],
                        'index' => $data['index'] - 1
                    ];
                }
                $sort->saveAll($array);
                $InfoModel->delete();

                $books = Db::query("select * from cash_book where state = 1 and month = ? and category = 'B' order by category asc, id asc", [$InfoModel['month']]);;
                $category_B = array_column($books, 'id');

                $result = [
                    'total' => self::getTotal($InfoModel['month'], $category_B),
                    'cur_row' => null,
                    'group' => InfoModel::where('is_light', 1)->where('month', $InfoModel['month'])->where('category', $InfoModel['category'])->count() > 0 ? 1 : null
                ];
            }

            if (($InfoModel['category'] == 'A' || $InfoModel['category'] == 'B')) {
                $result['rows'] = self::updateBetchBalance($InfoModel['month']);
            }
            return $result;

        });
    }

    public static function updateData(Request $request)
    {
        $token = Request::instance()->header('TOKEN');
        $result = JWT::verifyToken($token);
        $now = date('Y-m-d H:i:s');
        $parmas = $request->post();
        $baseInfo = InfoModel::get(['id' => $parmas['id']]);
        $month = $baseInfo['month'];
        $books = Db::query("select * from cash_book where state = 1 and month = ? and category = 'B' order by category asc, id asc", [$month]);;
        $category_B = array_column($books, 'id');
        $InfoModel = new InfoModel;
        if ($parmas['field'] == 'day') {
            $fields = [
                'weekday' => $parmas['weekday'],
                'day' => $parmas['day'],
                'issue' => $parmas['issue'],
            ];
            if ($baseInfo['category'] == 'D') {
                if ($fields['issue'] != null) {
                    $systemInfo = self::getSystemJson($baseInfo['month'], $baseInfo['sid']);
                    if (null != $systemInfo && null != $systemInfo['copy'] && null != $systemInfo['copy']['detail_rmb']) {
                        $fields['detail_rmb'] = $systemInfo['copy']['detail_rmb'];
                        $fields['title'] = $systemInfo['system']['month_format'] . $systemInfo['system']['title'];
                    } else {
                        $fields['detail_rmb'] = null;
                    }
                } else {
                    $fields['detail_rmb'] = null;
                }
            }
            if ($baseInfo['category'] == 'E') {
                if ($fields['issue'] != null) {
                    $systemInfo = self::getSystemJson($baseInfo['month'], $baseInfo['sid']);
                    if (null != $systemInfo && null != $systemInfo['copy'] && null != $systemInfo['copy']['detail_rmb']) {
                        $fields['detail_rmb'] = $systemInfo['copy']['detail_rmb'];
                        $fields['title'] = $systemInfo['system']['month_format'] . $systemInfo['system']['title'] . (number_format($fields['detail_rmb'], 2, '.', ','));
                    } else {
                        $fields['detail_rmb'] = null;
                    }
                } else {
                    $fields['detail_rmb'] = null;
                }
            }

            if ($baseInfo['category'] == 'F') {
                if ($fields['issue'] != null) {
                    $systemInfo = self::getSystemJson($baseInfo['month'], $baseInfo['sid']);
                    if (null != $systemInfo && null != $systemInfo['copy'] && null != $systemInfo['copy']['detail_rmb']) {
                        $fields['detail_money'] = $systemInfo['copy']['detail_rmb'];
                        $fields['title'] = $systemInfo['system']['month_format'] . $systemInfo['system']['title'] . '$' . (number_format($fields['detail_money'], 2, '.', ','));
                    } else {
                        $fields['detail_money'] = null;
                        $fields['detail_rmb'] = null;
                        $fields['real_rate'] = null;
                    }
                } else {
                    $fields['detail_money'] = null;
                    $fields['detail_rmb'] = null;
                    $fields['real_rate'] = null;
                }
            }
            if ($baseInfo['category'] == 'B' && $baseInfo['source'] == 'system') {
                //B类系统生成数据，需要清空数据
                if ($parmas['issue'] == null) {
                    $fields['detail_rmb'] = null;
                    $fields['money'] = null;
                    $fields['detail_income'] = null;
                    $fields['detail_outcome'] = null;
                } else {
                    $systemInfo = self::getSystemJson($baseInfo['month'], $baseInfo['sid']);
                    if (null != $systemInfo && null != $systemInfo['copy'] && null != $systemInfo['copy']['detail_rmb']) {
                        $fields['title'] = $systemInfo['system']['month_format'] . $systemInfo['system']['title'];
                        $fields['detail_rmb'] = $systemInfo['copy']['detail_rmb'];
                        if ($fields['detail_rmb'] > 0) {
                            $fields['detail_income'] = abs($fields['detail_rmb']);
                            $fields['detail_outcome'] = null;
                        } else {
                            $fields['detail_income'] = null;
                            $fields['detail_outcome'] = abs($fields['detail_rmb']);
                        }
                        $fields['money'] = null;
                    } else {
                        $fields['detail_rmb'] = null;
                        $fields['money'] = null;
                        $fields['detail_income'] = null;
                        $fields['detail_outcome'] = null;
                    }
                }
            }
        } else if ($parmas['field'] == 'remark') {
            $fields = [
                'remark' => $parmas['remark'],
            ];
        } else if ($parmas['field'] == 'title') {
            $fields = [
                'title' => $parmas['title'],
            ];
        } else if ($parmas['field'] == 'detail_payment') {
            $item = InfoModel::get($parmas['id']);
            $cb_id = BookModel::get(['month' => $item['month'], 'category' => 'A'])['id'];
            if ($parmas['detail_payment'] != null) {
                $fields = [
                    'category' => 'A',
                    'cb_id' => $cb_id,
                    'income' => null,
                    'outcome' => null,
                    'detail_income' => null,
                    'detail_outcome' => null,
                    'detail_payment' => $parmas['detail_payment'],
                    'money' => $parmas['detail_payment'],
                    'is_light' => null,
                ];
            } else {
                $fields = [
                    'detail_payment' => null,
                    'money' => null,
                    'category' => 'B',
                    'cb_id' => null,
                ];
            }

            if ($parmas['detail_payment'] != $baseInfo['detail_payment']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['detail_payment'],
                    'after' => $parmas['detail_payment'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }


        } else if ($parmas['field'] == 'money') {
            $fields = [
                'money' => $parmas['money'],
            ];
            if ($baseInfo['category'] == 'B') {
                if ($baseInfo['detail_rmb'] >= 0) {
                    $fields['detail_income'] = bcsub(abs($baseInfo['detail_rmb']), $fields['money'], 2);
                    $fields['detail_outcome'] = null;
                } else {
                    $fields['detail_outcome'] = bcadd(abs($baseInfo['detail_rmb']), $fields['money'], 2);
                    $fields['detail_income'] = null;
                }
            }
            if ($parmas['money'] != $baseInfo['money']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['money'],
                    'after' => $parmas['money'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }
        } else if ($parmas['field'] == 'detail_rmb') {
            if ($parmas['category'] == 'C') {
                $fields = [
                    'detail_rmb' => $parmas['detail_rmb'],
                    'detail_money' => null,
                    'real_rate' => null,
                    'budget_rate' => null,
                ];
            } else if ($parmas['category'] == 'B') {
                $fields = [
                    'detail_rmb' => $parmas['detail_rmb'],
                ];
                if ($parmas['detail_rmb'] == null) {
                    $fields['category'] = 'B';
                    $fields['cb_id'] = null;
                    $fields['detail_income'] = null;
                    $fields['detail_outcome'] = null;
                    $fields['money'] = null;
                } else {
                    $fields['cb_id'] = $parmas['cb_id'];
                    if ($parmas['detail_rmb'] > 0) {
                        bcsub(abs($parmas['detail_rmb']), $baseInfo['money']);
                        $fields['detail_income'] = bcsub(abs($parmas['detail_rmb']), $baseInfo['money'], 2);
                        $fields['detail_outcome'] = null;
                    } else {
                        $fields['detail_income'] = null;
                        $fields['detail_outcome'] = bcadd(abs($parmas['detail_rmb']), $baseInfo['money'], 2);
                    }
                }
            } else if ($parmas['category'] == 'D') {
                $fields = [
                    'detail_rmb' => $parmas['detail_rmb'],
                ];
            }
            if ($parmas['detail_rmb'] != $baseInfo['detail_rmb']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['detail_rmb'],
                    'after' => $parmas['detail_rmb'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }
        } else if ($parmas['field'] == 'income') {
            $fields = [
                'income' => $parmas['income'],
            ];
            if ($parmas['income'] != $baseInfo['income']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['income'],
                    'after' => $parmas['income'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }
        } else if ($parmas['field'] == 'outcome') {
            $fields = [
                'outcome' => $parmas['outcome'],
            ];
            if ($parmas['outcome'] != $baseInfo['outcome']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['outcome'],
                    'after' => $parmas['outcome'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }
        } else if ($parmas['field'] == 'detail_money') {
            $plan = PlanModel::get(['month' => $month]);
            $fields = [
                'detail_money' => $parmas['detail_money'],
            ];
            if ($fields['detail_money'] == null) {
                $fields['budget_rate'] = null;
                $fields['detail_rmb'] = null;
                $fields['real_rate'] = null;
            } else {
                if ($baseInfo['real_rate'] != null) {
                    $fields['detail_rmb'] = bcmul($baseInfo['real_rate'], $fields['detail_money'], 2);
                } else if ($plan['rate'] != null) {
                    $fields['budget_rate'] = $plan['rate'];
                    $fields['detail_rmb'] = bcmul($fields['budget_rate'], $fields['detail_money'], 2);
                }
            }

            if ($parmas['detail_money'] != $baseInfo['detail_money']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['detail_money'],
                    'after' => $parmas['detail_money'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }


        } else if ($parmas['field'] == 'real_rate') {
            $fields = [
                'real_rate' => $parmas['real_rate'],
            ];
            if ($baseInfo['category'] == 'C') {
                if ($fields['real_rate'] != null) {
                    $fields['budget_rate'] = null;
                    if ($baseInfo['detail_money'] != null) {
                        $fields['detail_rmb'] = bcmul($fields['real_rate'], $baseInfo['detail_money'], 2);
                    }
                } else {
                    $plan = PlanModel::get(['month' => $month]);
                    if ($plan['rate'] != null) {
                        $fields['budget_rate'] = $plan['rate'];
                        $fields['detail_rmb'] = bcmul($fields['budget_rate'], $baseInfo['detail_money'], 2);
                    }
                }
            } else if ($baseInfo['category'] == 'F') {
                if ($fields['real_rate'] != null && $baseInfo['detail_money'] != null) {
                    $fields['detail_rmb'] = bcmul($fields['real_rate'], $baseInfo['detail_money'], 2);
                } else {
                    $fields['detail_rmb'] = null;
                }
            }
            if ($parmas['real_rate'] != $baseInfo['real_rate']) {
                $json = [
                    'first_name' => substr($result['data']['username'], 0, 1),
                    'username' => $result['data']['username'],
                    'update_time' => $now,
                    'before' => $baseInfo['real_rate'],
                    'after' => $parmas['real_rate'],
                ];
                $record = $baseInfo['record'];
                if (null == $record) {
                    $record = [$parmas['field'] => $json];
                } else {
                    $record = json_decode($record, true);
                    $record[$parmas['field']] = $json;
                }
                $fields['record'] = json_encode($record, JSON_UNESCAPED_UNICODE);
            }
        }
        $InfoModel->save($fields, ['id' => $parmas['id']]);

        //回显
        $baseInfoEdit = InfoModel::get(['id' => $parmas['id']]);
        if ($baseInfoEdit['category'] == 'B' && $baseInfoEdit['cb_id'] != null) {
            foreach ($category_B as $cb_id) {
                if ($cb_id == $baseInfoEdit['cb_id']) {
                    $baseInfoEdit['detail_income_' . $cb_id] = $baseInfoEdit['detail_income'];
                    $baseInfoEdit['detail_outcome_' . $cb_id] = $baseInfoEdit['detail_outcome'];
                } else {
                    $baseInfoEdit['detail_income_' . $cb_id] = null;
                    $baseInfoEdit['detail_outcome_' . $cb_id] = null;
                }
            }
        }
        if ($baseInfoEdit['record'] != null) {
            $baseInfoEdit['record'] = json_decode($baseInfoEdit['record'], true);
        }
        if ($baseInfoEdit['category'] == 'A' || $baseInfoEdit['category'] == 'B') {
            $baseInfoEdit['pid'] = 'AB';
        } else {
            $baseInfoEdit['pid'] = $baseInfoEdit['category'];
        }
        $result = [
            'row' => $baseInfoEdit,
            'total' => self::getTotal($month, $category_B)
        ];
        if (($baseInfoEdit['category'] == 'A' || $baseInfoEdit['category'] == 'B') &&
            ($parmas['field'] == 'detail_rmb' || $parmas['field'] == 'detail_payment' || $parmas['field'] == 'money' || ($parmas['field'] == 'day' && $baseInfoEdit['source'] == 'system'))) {
            $result['rows'] = self::updateBetchBalance($month);
        }
        return $result;

    }

    public static function updateBudgerate($month, $budget_rate)
    {
        $books = Db::query("select * from cash_book where state = 1 and month = ? and category = 'B' order by category asc, id asc", [$month]);;
        $category_B = array_column($books, 'id');
        $infos = Db::query("select * from cash_info where month = ? and detail_money is not null and real_rate is null and category = 'C'", [$month]);
        $infos_update = new InfoModel;
        $ids = [];
        $array = [];
        foreach ($infos as $data) {
            $ids[] = $data['id'];
            $array[] = [
                'id' => $data['id'],
                'budget_rate' => $budget_rate,
                'detail_rmb' => bcmul($budget_rate, $data['detail_money'], 2)
            ];
        }
        $infos_update->saveAll($array);
        $PlanModel = new PlanModel();
        $PlanModel->save([
            'rate' => $budget_rate
        ], ['month' => $month]);
        return [
            'list' => count($ids) == 0 ? [] : InfoModel::all($ids),
            'total' => self::getTotal($month, $category_B)
        ];
    }

    public static function getSystemJson($month, $sid)
    {
        $systems = json_decode(file_get_contents('files/system.json'), true);
        $single = array_filter($systems, function ($obj) use ($sid) {
            return $obj['sid'] == $sid;
        });
        if (count($single) != 1) {
            return null;
        }
        $single = array_values($single)[0];
        $operate = $single['month_operate'];
        $single['cur_month'] = $month;
        if ($operate >= 0) {
            $date = DateTime::createFromFormat('Ym', $month);
            $date->add(new DateInterval('P' . $operate . 'M'));
            $single['month'] = $date->format('Ym');
            $single['month_format'] = $date->format('Y年n月');
        } else if ($operate < 0) {
            $date = DateTime::createFromFormat('Ym', $month);
            $date->sub(new DateInterval('P' . (0 - $operate) . 'M'));
            $single['month'] = $date->format('Ym');
            $single['month_format'] = $date->format('Y年n月');
        }
        $copy = SpecialDataModel::get(['month' => $single['month'], 'sid' => $single['sid']]);
        if(null == $copy){
            $copy = [
                'month' => $single['month'], 'sid' => $single['sid'], 'detail_rmb' => null
            ];
        }
        return [
            'system' => $single,
            'copy' => $copy
        ];
    }

    public static function deletePlan($month)
    {
        Db::transaction(function () use ($month) {
            PlanModel::where('month', '=', $month)->delete();
            BookModel::where('month', '=', $month)->delete();
            InfoModel::where('month', '=', $month)->delete();
        });
    }

    public static function copyPlan($month)
    {

        return Db::transaction(function () use ($month) {

            $cur_month = date('Ym');
            $max_month = PlanModel::max('month');
            $max_issue = DateTime::createFromFormat('Ym', $max_month);
            $max_issue->add(new DateInterval('P1M'));

            $max_y = $max_issue->format('Y');
            $max_m = $max_issue->format('m');
            $next_max_day = cal_days_in_month(CAL_GREGORIAN, $max_m, $max_y);

            $next_month = $max_issue->format('Ym');
            if (($next_month - $cur_month) > 2) {
                throw new BaseException([
                    'msg' => '不可复制：已存在本月下下月的明细表',
                    'code' => 9527,
                    'errorCode' => 400
                ]);
            }

            //保存计划
            $plan_new = new PlanModel([
                'month' => $next_month,
                'state' => 1,
                'create_time' => date('Y-m-d H:i:s'),
                'remark' => PlanModel::get(['month' => $month])['remark']
            ]);
            $plan_new->save();

            //保存账本
            $books = BookModel::all(['month' => $month]);
            $books_save = new BookModel();
            foreach ($books as $book) {
                $books_new[] = [
                    'title' => $book['title'],
                    'category' => $book['category'],
                    'state' => $book['state'],
                    'is_merge' => $book['is_merge'],
                    'month' => $next_month,
                ];
            }
            $books_save->saveAll($books_new);

            $map_system = [];
            //系统数据查询
            $systems = json_decode(file_get_contents('files/system.json'), true);
            foreach ($systems as $key => $system) {
                $item = self::getSystemJson($next_month, $system['sid']);
                if ($item != null && $item['copy'] != null) {
                    $temp = [];
                    $temp['month'] = $next_month;
                    $temp['source'] = 'system';
                    $temp['sid'] = $system['sid'];
                    $temp['category'] = $system['category'];
                    $temp['title'] = $item['system']['month_format'] . $item['system']['title'];
                    if ($system['category'] == 'B') {
//                        $temp['detail_rmb'] = $item['copy']['detail_rmb'];
//                        if ($temp['detail_rmb'] < 0) {
//                            $temp['detail_outcome'] = abs($temp['detail_rmb']);
//                        } else {
//                            $temp['detail_income'] = $temp['detail_rmb'];
//                        }
                    } else if ($system['category'] == 'D') {
//                        $temp['detail_rmb'] = $item['copy']['detail_rmb'];
                    } else if ($system['category'] == 'E') {
                        $temp['title'] = $temp['title'] . $item['copy']['detail_rmb'];
//                        $temp['detail_rmb'] = $item['copy']['detail_rmb'];
                    } else if ($system['category'] == 'F') {
                        $temp['title'] = $temp['title'] . '$' . $item['copy']['detail_rmb'];
//                        $temp['detail_money'] = $item['copy']['detail_rmb'];
                    }
                    $book = null;
                    if ($system['category'] == 'B') {
                        $book = BookModel::get(['month' => $next_month, 'title' => $system['category_title']]);
                    } else {
                        $book = BookModel::get(['month' => $next_month, 'category' => $system['category']]);
                    }
                    if ($book != null) {
                        $temp['cb_id'] = $book['id'];
                        if (!empty($temp)) {
                            $map_system[$temp['sid']] = $temp;
                        }
                    }
                }
            }

            $weekdays = array("日", "一", "二", "三", "四", "五", "六");

            $list = InfoModel::all(function ($query) use ($month) {
                $query->where('month', $month)->order('index', 'asc');
            });

            $infos_save = new InfoModel();
            $temp_save = [];
            foreach ($list as $temp) {
                $day = $temp['day'];
                $issue = null;
                $weekday = null;
                if ($day != null) {
                    $day = $day > $next_max_day ? $next_max_day : $day;
                    $issue = $next_month . ($day < 10 ? ('0' . $day) : $day);
                    $weekday = $weekdays[date("w", strtotime($issue))];
                    $issue = date('Y-m-d', strtotime($issue));
                }
                if ($temp['sid'] != null) {
                    if (array_key_exists($temp['sid'], $map_system)) {
                        $temp_map = $map_system[$temp['sid']];
                        $temp_map['day'] = $day;
                        $temp_map['issue'] = $issue;
                        $temp_map['weekday'] = $weekday;
                        $temp_map['remark'] = $temp['remark'];
                        $temp_save[] = $temp_map;
                    }
                } else if ($temp['category'] == 'C') {
                    $book = BookModel::get(['month' => $next_month, 'category' => $temp['category']]);
                    if (null != $book) {
                        if(null != $temp['detail_rmb'] && null == $temp['detail_money']){
                            $temp_save[] = [
                                'cb_id' => $book['id'],
                                'category' => $temp['category'],
                                'title' => $temp['title'],
                                'month' => $next_month,
                                'issue' => $issue,
                                'weekday' => $weekday,
                                'day' => $day,
                                'source' => 'manually',
                                'remark' => $temp['remark'],
                                'detail_rmb' => $temp['detail_rmb'],
                            ];
                        }else{
                            $temp_save[] = [
                                'cb_id' => $book['id'],
                                'category' => $temp['category'],
                                'title' => $temp['title'],
                                'month' => $next_month,
                                'issue' => $issue,
                                'weekday' => $weekday,
                                'day' => $day,
                                'source' => 'manually',
                                'remark' => $temp['remark'],
                            ];
                        }

                    }
                } else if ($temp['category'] == 'A') {
                    $book = BookModel::get(['month' => $next_month, 'category' => $temp['category']]);
                    if (null != $book) {
                        $temp_save[] = [
                            'cb_id' => $book['id'],
                            'category' => $temp['category'],
                            'title' => $temp['title'],
                            'month' => $next_month,
                            'issue' => $issue,
                            'weekday' => $weekday,
                            'day' => $day,
                            'source' => 'manually',
                            'remark' => $temp['remark'],
                            'detail_payment' => $temp['detail_payment'],
                        ];
                    }
                } else if ($temp['category'] == 'B') {
                    $cb_id = null;
                    if ($temp['cb_id'] != null) {
                        $book = BookModel::get(['month' => $next_month, 'title' => BookModel::get(['id' => $temp['cb_id']])['title']]);
                        $cb_id = $book['id'];
                    }
                    $temp_bean = [
                        'cb_id' => $cb_id,
                        'category' => $temp['category'],
                        'title' => $temp['title'],
                        'month' => $next_month,
                        'issue' => $issue,
                        'weekday' => $weekday,
                        'day' => $day,
                        'source' => 'manually',
                        'remark' => $temp['remark'],
                        'income' => $temp['income'],
                        'outcome' => $temp['outcome'],
                        'detail_rmb' => $temp['detail_rmb'],
                    ];
                    if ($temp['detail_rmb'] < 0) {
                        $temp_bean['detail_outcome'] = $temp['detail_rmb'];
                    } else {
                        $temp_bean['detail_income'] = $temp['detail_rmb'];
                    }
                    $temp_save[] = $temp_bean;
                }
            }
            foreach ($temp_save as $key => $value) {
                $temp_save[$key]['index'] = $key + 1;
            }
            $infos_save->saveAll($temp_save);
            return [
                'month' => $next_month,
                '$infos' => $temp_save
            ];
        });
    }

    public static function getRate($issue)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, config('const.em_rate_api') . '?issue=' . $issue);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $response = curl_exec($ch);
        curl_close($ch);
        return json_decode($response);
    }

    public static function updateBetchBalance($month)
    {
        $infos = Db::query("select cash_info.* from cash_info where cash_info.month = ? and category in ('A', 'B') order by cash_info.index asc", [$month]);
        $cb_ids = Db::query("select id from cash_book where $month = ? and category = 'B' and state = 1", [$month]);

        $balance = null;
        for ($i = 0; $i < count($infos); $i++) {
            foreach ($cb_ids as $cb_id) {
                $infos[$i]['detail_income_' . $cb_id['id']] = null;
                $infos[$i]['detail_outcome_' . $cb_id['id']] = null;
            }
            if ($infos[$i]['category'] == 'B' && $infos[$i]['cb_id'] != null) {
                if ($infos[$i]['detail_rmb'] != null) {
                    if ($infos[$i]['detail_rmb'] > 0) {
                        $infos[$i]['detail_income_' . $infos[$i]['cb_id']] = bcsub(abs($infos[$i]['detail_rmb']), $infos[$i]['money'],2);
                        $infos[$i]['detail_outcome_' . $infos[$i]['cb_id']] = null;
                    } else {
                        $infos[$i]['detail_income_' . $infos[$i]['cb_id']] = null;
                        $infos[$i]['detail_outcome_' . $infos[$i]['cb_id']] = bcadd(abs($infos[$i]['detail_rmb']), $infos[$i]['money'], 2);
                    }
                }
            }
            $balance = bcsub(bcadd(bcadd($balance, $infos[$i]['money'], 2), $infos[$i]['detail_income'],2), $infos[$i]['detail_outcome'], 2);
//            $balance = bcadd(bcadd(bcadd($infos[$i]['detail_income'], $infos[$i]['detail_outcome'], 2), $infos[$i]['money'], 2), $balance, 2);
            if ($infos[$i]['money'] == null && $infos[$i]['detail_income'] == null && $infos[$i]['detail_outcome'] == null) {
                if($infos[$i]['category'] == 'A'){
                    $infos[$i]['balance'] = $balance;
                }else{
                    $infos[$i]['balance'] = null;
                }
            } else {
                $infos[$i]['balance'] = $balance;
            }
        }
        return $infos;
    }

    public static function generate()
    {
        $temp_save = Db::query("SELECT
                                        *
                                    FROM
                                        cash_info
                                    ORDER BY
                                        category asc,
                                        isnull(issue) ASC,
                                        issue ASC,
                                        isnull(title) ASC;");
        foreach ($temp_save as $key => $value) {
            $temp_save[$key]['index'] = $key + 1;
        }
        $infos_save = new InfoModel();
        $infos_save->saveAll($temp_save);
        return;
        $next_month = '202407';
        $temp_save = [];
        $systems = json_decode(file_get_contents('files/system.json'), true);
        foreach ($systems as $key => $system) {
            $item = self::getSystemJson($next_month, $system['sid']);
            if ($item != null && $item['copy'] != null) {
                $temp = [];
                $temp['month'] = $next_month;
                $temp['source'] = 'system';
                $temp['sid'] = $system['sid'];
                $temp['category'] = $system['category'];
                $temp['title'] = $item['system']['month_format'] . $item['system']['title'];
                if ($system['category'] == 'B') {
                    $temp['detail_rmb'] = $item['copy']['detail_rmb'];
                    if ($temp['detail_rmb'] < 0) {
                        $temp['detail_outcome'] = abs($temp['detail_rmb']);
                    } else {
                        $temp['detail_income'] = $temp['detail_rmb'];
                    }
                } else if ($system['category'] == 'D') {
                    $temp['detail_rmb'] = $item['copy']['detail_rmb'];
                } else if ($system['category'] == 'E') {
                    $temp['title'] = $temp['title'] . $item['copy']['detail_rmb'];
                    $temp['detail_rmb'] = $item['copy']['detail_rmb'];
                } else if ($system['category'] == 'F') {
                    $temp['title'] = $temp['title'] . '$' . $item['copy']['detail_rmb'];
                    $temp['detail_money'] = $item['copy']['detail_rmb'];
                }
                $book = null;
                if ($system['category'] == 'B') {
                    $book = BookModel::get(['month' => $next_month, 'title' => $system['category_title']]);
                } else {
                    $book = BookModel::get(['month' => $next_month, 'category' => $system['category']]);
                }
                if ($book != null) {
                    $temp['cb_id'] = $book['id'];
                    if (!empty($temp)) {
                        $temp_save[] = $temp;
                    }
                }
            }
        }
        $infos_save = new InfoModel();
        $infos_save->saveAll($temp_save);
    }

}
